package com.ihr360.rest.core;

import com.ihr360.rest.config.Ihr360RestConfiguration;
import com.ihr360.rest.webmvc.json.Ihr360EnumTranslator;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.rest.core.mapping.ResourceDescription;
import org.springframework.data.util.AnnotatedTypeScanner;

import java.util.HashSet;
import java.util.Set;

@Configuration
public class Ihr360RestDataMvcConfiguration {
    private static final String SCAN_PACKAGE_SPAPATER = ",";
    @Autowired
    ApplicationContext applicationContext;

    @Value("${com.ihr360.rest.projection.scan:com.ihr360.rest.projection}")
    private String packagesToScanConfig;

    @Bean
    public ProjectionFactory projectionFactory(){
        return new SpelAwareProxyProjectionFactory();
    }

    /**
     * Main configuration for the REST exporter.
     */
    @Bean
    public Ihr360RestConfiguration ihr360RestConfiguration() {

        Ihr360ProjectionDefinitionConfiguration configuration = new Ihr360ProjectionDefinitionConfiguration();

        // Register projections found in packages
        for (Class<?> projection : getProjections(scanPackages())) {
            configuration.addProjection(projection);
        }

        Ihr360RestConfiguration config = new Ihr360RestConfiguration(configuration, ihr360MetadataConfiguration(),
                ihr360EnumTranslator());

        //configurerDelegate.configureRepositoryRestConfiguration(config);

        return config;
    }

    private Set<String> scanPackages() {
        Set<String> packagesToScan = new HashSet<>();
        String[] packages = packagesToScanConfig.split(SCAN_PACKAGE_SPAPATER);
        for (String pkg : packages) {
            packagesToScan.add(pkg);
        }
        return packagesToScan;
    }

    @Bean
    public Ihr360MetadataConfiguration ihr360MetadataConfiguration() {
        return new Ihr360MetadataConfiguration();
    }

    @Bean
    public Ihr360EnumTranslator ihr360EnumTranslator() {
        return new Ihr360EnumTranslator(ihr360ResourceDescriptionMessageSourceAccessor());
    }


    /**
     * The {@link MessageSourceAccessor} to provide messages for {@link ResourceDescription}s being rendered.
     *
     * @return
     */
    @Bean
    public MessageSourceAccessor ihr360ResourceDescriptionMessageSourceAccessor() {

        try {

            PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
            propertiesFactoryBean.setLocation(new ClassPathResource("rest-default-messages.properties"));
            propertiesFactoryBean.afterPropertiesSet();

            ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
            messageSource.setBasename("classpath:rest-messages");
            messageSource.setCommonMessages(propertiesFactoryBean.getObject());
            messageSource.setDefaultEncoding("UTF-8");

            return new MessageSourceAccessor(messageSource);

        } catch (Exception o_O) {
            throw new BeanCreationException("resourceDescriptionMessageSourceAccessor", "", o_O);
        }
    }

    private Set<Class<?>> getProjections(Set<String> packages) {


        AnnotatedTypeScanner scanner = new AnnotatedTypeScanner(Ihr360Projection.class);
        scanner.setEnvironment(applicationContext.getEnvironment());
        scanner.setResourceLoader(applicationContext);

        return scanner.findTypes(packages);
    }

}